/*
  HardwareSerial.h - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 28 September 2010 by Mark Sproul
  Modified 14 August 2012 by Alarus
  Modified 3 December 2013 by Matthijs Kooijman
*/

#ifndef __HARDWARESERIAL_H__
#define __HARDWARESERIAL_H__
#include <Arduino.h>
#include "pins_arduino.h"
#include "Stream.h"
#include "RingBuffer.h"

typedef enum
{
  HALF_DUPLEX_DISABLED,
  HALF_DUPLEX_ENABLED
} HalfDuplexMode_t;

#define SERIAL_8N1 0x06
#define SERIAL_8N2 0x0E
#define SERIAL_7E1 0x24
#define SERIAL_8E1 0x26
#define SERIAL_7E2 0x2C
#define SERIAL_8E2 0x2E
#define SERIAL_7O1 0x34
#define SERIAL_8O1 0x36
#define SERIAL_7O2 0x3C
#define SERIAL_8O2 0x3E

class HardwareSerial : public Stream
{
protected:
  RingBuffer _rxBuffer;
public:
  HardwareSerial(USART_TypeDef *peripheral);
  HardwareSerial(uint32_t _rx, uint32_t _tx);
  HardwareSerial(PinName _rx, PinName _tx);
  HardwareSerial(uint32_t _rxtx);
  HardwareSerial(PinName _rxtx);

  void begin(unsigned long baud)
  {
    begin(baud, SERIAL_8N1);
  }

  void begin(unsigned long, uint8_t);
  void end();

  
  virtual int available(void);
  virtual int peek(void);
  virtual int read(void);
  // virtual int availableForWrite(void);
  virtual void flush(void);
  virtual size_t write(uint8_t);
  
  void IrqHandler();

  using Print::write;
  operator bool() { return true; }

private:
  void init(PinName _rx, PinName _tx);
  void initUart(USART_TypeDef *peripheral, uint32_t _rx, uint32_t _tx);
private:
  USART_TypeDef*  _usert_x;
  uint16_t        _usert_mode;
  uint8_t         _config;
  unsigned long   _baud;
};

extern HardwareSerial Serial1;
extern HardwareSerial Serial2;
extern HardwareSerial Serial3;
extern HardwareSerial Serial4;
extern HardwareSerial Serial5;
extern HardwareSerial Serial6;
extern HardwareSerial Serial7;
extern HardwareSerial Serial8;
extern HardwareSerial Serial9;
extern HardwareSerial Serial10;

#if SERIAL_UART_INSTANCE == 1
# define ENABLE_HWSERIAL1
# ifndef Serial
#   define Serial Serial1
#   define serialEvent serialEvent1
# endif
#elif SERIAL_UART_INSTANCE == 2
# define ENABLE_HWSERIAL2
# ifndef  Serial
#   define Serial Serial2
#   define serialEvent serialEvent2
# endif
#elif SERIAL_UART_INSTANCE == 3
# define ENABLE_HWSERIAL3
# ifndef  Serial
#   define Serial Serial3
#   define serialEvent serialEvent3
# endif
#endif

#ifdef ENABLE_HWSERIAL1
# if defined(USART1_BASE) 
#   define HAVE_HWSERIAL1
# endif
#endif

#ifdef ENABLE_HWSERIAL2
# ifdef USART2_BASE
#   define HAVE_HWSERIAL2
# endif
#endif

#ifdef ENABLE_HWSERIAL3
# ifdef USART3_BASE
#   define HAVE_HWSERIAL3
# endif
#endif

extern void serialEventRun(void);

#endif // __HARDWARESERIAL_H__